#pragma
#include<iostream>
#include<string>
#include<unistd.h>
#include"Thread.hpp"
#include<vector>
#include<queue>
#include"Log.hpp"
using namespace std;
static const int defaultnum = 5;
template <typename T>
class ThreadPool
{
private:
//懒汉模式
    ThreadPool(int thread_num=defaultnum):thread_num(thread_num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }
    ThreadPool(const ThreadPool<T> &) = delete;
    void operator=(const ThreadPool<T> &) = delete;
    void LockQ()
    {
        pthread_mutex_lock(&_mutex);
    }
    void UnlockQ()
    {
        pthread_mutex_unlock(&_mutex);
    }
    void WakeUp()
    {
        pthread_cond_signal(&_cond);
    }
    void WakeAll()
    {
        pthread_cond_broadcast(&_cond);
    }
    void Sleep()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }
    bool isEmpty()
    {
        return task_queue.empty();
    }
     void Init()
    {
        func_t func = bind(&ThreadPool::Handler, this,placeholders::_1);
        for (int i = 0; i < thread_num; i++)
        {
            string name = "thread-" + to_string(i + 1);
            _threads.emplace_back(name,func);
        }
    }
    void Start()
    {
        isrunning = true;
        for (auto &thread : _threads)
        {
            thread.Start();
        }
    }
    void Handler(const string name)
    {
        while(1)
        {
            LockQ();
            while(isEmpty()&&isrunning)
            {
                sleep_num++;
                Sleep();
                sleep_num--;
            }
            //没任务了而且想退出
            if(!isrunning&&isEmpty())
            {
                LOG(DEBUG,"%s out\n",name.c_str());
                UnlockQ();
                break;
            }

            //有任务
            T t = task_queue.front();
            task_queue.pop();
            UnlockQ();

            t();//不用在临界区，相当于隔绝，自己去处理
            LOG(DEBUG,"%s finish\n",name.c_str());
        }
    }
public:
//懒汉模式
    static ThreadPool<T>* GetThreadPool()
    {
        //保证单例就一个且获取安全
        if(_tp==nullptr)
        {
            LockGuard(&ThreadPool<T>::sig_mutex);
            if (_tp == nullptr)
            {
                LOG(INFO, "create ThreadPool\n");
                _tp = new ThreadPool<T>();
                _tp->Init();
                _tp->Start();
            }
        }
        return _tp;
    }
   
    void Stop()
    {
        LockQ();
        isrunning = false;
        WakeAll();
        UnlockQ();
    }
    void Enqueue(const T& in )
    {
        LockQ();
        if(isrunning)
        {
            task_queue.push(in);
            if(sleep_num>0)
            WakeUp();
        }
        UnlockQ();
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    int thread_num;
    vector<Thread> _threads;
    queue<T> task_queue;
    bool isrunning;
    pthread_mutex_t _mutex;//对task_queue保护
    pthread_cond_t _cond;
    int sleep_num=0 ;
    static ThreadPool<T> *_tp;
    static pthread_mutex_t sig_mutex;
};
template <typename T>
ThreadPool<T> *ThreadPool<T>::_tp = nullptr;
template <typename T>
pthread_mutex_t ThreadPool<T>::sig_mutex = PTHREAD_MUTEX_INITIALIZER;
